/**
 * 
 */
package net.xfok.db.sqlite;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import net.xfok.db.ORM;
import net.xfok.db.Query;
import net.xfok.db.Reflect;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.ParseException;
import android.util.Log;

/**
 * @author howard
 *
 */
public class DAO {
	private final static String TAG="DAO";
	protected int version=3;
	protected String dbName;
	protected String tableName;
	protected Object obj;
	protected Context context;
	private DatabaseHelper dbHelper;
	private SQLiteDatabase db;
	private String[] columns;
	private boolean printQuery=false;
	
	public void printQuery(boolean printQuery){
		this.printQuery=printQuery;
	}
	
	public boolean getPrintQuery(){
		return printQuery;
	}

	public DatabaseHelper getDbHelper(){
		return dbHelper;
	}
	
	public DAO(Context context,String dbName,Object obj){
		this.context=context;
		this.dbName=dbName;
		this.obj=obj;		
		this.tableName=obj.getClass().getSimpleName().toLowerCase();
		this.columns=genColumns(obj);
		dbHelper = new DatabaseHelper(context, dbName, null,version);
	}
	
	public DAO(Context context,String dbName,Object obj,int version){
		this.context=context;
		this.dbName=dbName;
		this.obj=obj;		
		this.version=version;
		this.tableName=obj.getClass().getSimpleName().toLowerCase();
		this.columns=genColumns(obj);
		dbHelper = new DatabaseHelper(context, dbName, null,version);
	}
	
	public boolean createTable(){		
		try{
			db = dbHelper.getWritableDatabase();
			String query=Query.create(obj, tableName);
			if(printQuery){
				Log.i(TAG, "QUERY:"+query.toUpperCase());
			}	
			db.execSQL(query);
			return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean dropTable(){		
		String query=Query.drop(tableName);
		try {
			db = dbHelper.getWritableDatabase();
			if(printQuery){
				Log.i(TAG, "QUERY:"+query.toUpperCase());
			}
			db.execSQL(query);
			close();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}		
		return false;
	}
	
	public boolean create(Object obj){
		try{
			db = dbHelper.getWritableDatabase();
			String query=Query.insert(obj, tableName);
			if(printQuery){
				Log.i(TAG, "QUERY:"+query.toUpperCase());
			}	
			db.execSQL(query);
			close();
			return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean update(Object obj){
		try{
			db = dbHelper.getWritableDatabase();
			String query=Query.update(obj, tableName);
			if(printQuery){
				Log.i(TAG, "QUERY:"+query.toUpperCase());
			}	
			db.execSQL(query);
			close();
			return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean delete(int id){
		try{
			db = dbHelper.getWritableDatabase();
			db.delete(tableName, ORM.FIELD_ID_NAME+"=?", new String[]{String.valueOf(id)});
			close();
			return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean delete(String where){
		try{
			db = dbHelper.getWritableDatabase();
			db.delete(tableName, where, null);
			close();
			return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public Object select(int id) {		
		try{
			db = dbHelper.getReadableDatabase();
			Cursor cursor = db.query(tableName, columns, ORM.FIELD_ID_NAME+"=?", new String[]{String.valueOf(id)}, null,
					null, null);
			if(cursor.moveToFirst()){	
				return cursorToObject(cursor, obj);
			}		
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	public Cursor select(String selection) {			
		try{
			db = dbHelper.getReadableDatabase();
			Cursor cursor = db.query(tableName, columns, selection, null, null,
					null, null);
			return cursor;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	public Cursor select() {			
		try{
			db = dbHelper.getReadableDatabase();
			Cursor cursor = db.query(tableName, columns, null, null, null,
					null, null);
			return cursor;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	public List<Object> selectAll() {	
		List<Object> list = new ArrayList<Object>();
		try{
			Cursor cursor=select();
			while(cursor.moveToNext()){
				obj=obj.getClass().newInstance();
				list.add(cursorToObject(cursor, obj));
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return list;
	}
	
	public int count(){
		return select().getCount();
	}
	
	public int count(String selection){
		return select(selection).getCount();
	}
	
	public List<Object> selectAll(String selection) {
		Cursor cursor=select(selection);
		List<Object> list = new ArrayList<Object>();
		try{
			while(cursor.moveToNext()){
				obj=obj.getClass().newInstance();
				list.add(cursorToObject(cursor, obj));
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return list;
	}
	
	public void close(){
		if(db!=null&&db.isOpen()){
			db.close();
		}
	}
	
	public String[] genColumns(Object obj){
		Field[] fields = Reflect.genFileds(obj);
		String[] columns=new String[fields.length];
		int i=0;
		for (Field field : fields) {	
			columns[i++]=field.getName();
		}
		return columns;
	}
	
	public Object cursorToObject(Cursor cursor,Object obj) throws SQLException, ParseException, java.text.ParseException{
		Field[] fields = Reflect.genFileds(obj);
		for (Field field : fields) {		
			Object value = null;
			String type=field.getType().getSimpleName();
			if (type.equals(ORM.FIELD_TYPE_INT)) {			
				value = cursor.getInt(cursor.getColumnIndex(field.getName()));
			}
			if (type.equals(ORM.FIELD_TYPE_LONG)) {			
				value = cursor.getLong(cursor.getColumnIndex(field.getName()));;
			}
			if(type.equals(ORM.FIELD_TYPE_FLOAT)){
				value=cursor.getFloat(cursor.getColumnIndex(field.getName()));
			}
			if(type.equals(ORM.FIELD_TYPE_STRING)){
				value = cursor.getString(cursor.getColumnIndex(field.getName()));
			}
			if(type.equals(ORM.FIELD_TYPE_DATE)){						
				value=new SimpleDateFormat(ORM.DEFAULT_DATE_FORMAT).parse(cursor.getString(cursor.getColumnIndex(field.getName())));
			}
			Reflect.invokeSet(obj, field, value);
		}
		return obj;
	}
}
